package cn.buk.qms.service;

import cn.buk.api.airskyhk.dto.AirShoppingRequest;
import cn.buk.api.airskyhk.dto.OriginDestRequest;
import cn.buk.api.airskyhk.dto.PaxQuery;
import cn.buk.common.JsonResult;
import cn.buk.common.dto.CommonDto;
import cn.buk.common.dto.eterm.FfDto;
import cn.buk.common.flight.dto.FlightInfoDto;
import cn.buk.common.flight.intl.response.IntlFlightResponseDto;
import cn.buk.common.sc.CommonSearchCriteria;
import cn.buk.common.util.HttpUtil;
import cn.buk.flight.dao.FlightDao;
import cn.buk.flight.entity.AirlineTable;
import cn.buk.flight.entity.FdRequest;
import cn.buk.flight.entity.FdResult;
import cn.buk.flight.entity.SkInfo;
import cn.buk.tms.dao.TransactionDao;
import cn.buk.tms.entity.misc.EnterpriseBalance;
import cn.buk.tms.entity.config.EtermEntConfig;
import cn.buk.common.util.BukEtermClient;
import cn.buk.common.util.DateUtil;
import cn.buk.common.util.FlightUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;

import static cn.buk.common.Constant.DATE_YYYY_MM_DD;
import static cn.buk.common.Constant.SUCCESS;

/**

 * @date 2013-8-18
 * @author yfdai
 */
@Component
public class FlightServiceImpl extends BaseAbstractService implements FlightService {

    private static final Logger logger = LogManager.getLogger(FlightServiceImpl.class);

    @Value("${api_flight_url}")
    private String apiUrl;

    @Autowired
    private FlightDao flightDao;

    @Autowired
    private TransactionDao transactionDao;

    /**
     * 保存用户的航线价格请求
     */
    @Override
    public JsonResult createPriceRequest(final int enterpriseId, final String carrier, final String dport, final String aport, final String ddate) {
        final int minPoints = 20000;
        //判断用户的积分是否有5000以上
        EnterpriseBalance bal = enterpriseDao.getEnterpriseBalance(enterpriseId);

        if (bal == null || bal.getBitcoinBalance() < minPoints) {
            logger.info("Your points must be greater than {}", minPoints);
            return JsonResult.createJsonResult(-1, "积分余额需要 " + minPoints + "以上");
        }
        logger.info("Your points is {}", bal.getBitcoinBalance());

        if (carrier == null || dport == null || aport == null || carrier.length() != 2 || dport.length() == 0 || aport.length() == 0) {
            return JsonResult.createJsonResult(0, "请检查输入的数据项");
        }

        List<FdRequest> list = new ArrayList<>();

        Date fdDate = DateUtil.getTomorrowDate();

        try {
            fdDate = DateUtil.convertToDate(ddate, DATE_YYYY_MM_DD);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }

        if (dport.length() == 3 && aport.length() == 3) {
            FdRequest fdRequest = new FdRequest();
            fdRequest.setEnterpriseId(enterpriseId);
            fdRequest.setCarrier(carrier);
            fdRequest.setDport(dport);
            fdRequest.setAport(aport);
            fdRequest.setDdate(fdDate);

            list.add(fdRequest);
        } else {
            //清空所有之前的fd request
            deleteAllPriceRequest(enterpriseId);

            List<AirlineTable> airlineTables = flightDao.searchAirline(carrier);

            if ("*".equalsIgnoreCase(dport) && "*".equalsIgnoreCase(aport)) {
                //all to all
                for (AirlineTable airline : airlineTables) {
                    FdRequest fdRequest = new FdRequest();
                    fdRequest.setEnterpriseId(enterpriseId);
                    fdRequest.setCarrier(carrier);
                    fdRequest.setDport(airline.getDport());
                    fdRequest.setAport(airline.getAport());
                    fdRequest.setDdate(fdDate);

                    list.add(fdRequest);
                }
            } else if ("*".equalsIgnoreCase(dport) && aport.length() == 3) {
                //all to one
                for(AirlineTable airline: airlineTables) {
                    if (airline.getAport().equalsIgnoreCase(aport)) {
                        FdRequest fdRequest = new FdRequest();
                        fdRequest.setEnterpriseId(enterpriseId);
                        fdRequest.setCarrier(carrier);
                        fdRequest.setDport(airline.getDport());
                        fdRequest.setAport(aport);
                        fdRequest.setDdate(fdDate);

                        list.add(fdRequest);
                    }
                }
            } else if (dport.length() == 3 && "*".equalsIgnoreCase(aport)) {
                //one to all
                for(AirlineTable airline: airlineTables) {
                    if (airline.getDport().equalsIgnoreCase(dport)) {
                        FdRequest fdRequest = new FdRequest();
                        fdRequest.setEnterpriseId(enterpriseId);
                        fdRequest.setCarrier(carrier);
                        fdRequest.setDport(dport);
                        fdRequest.setAport(airline.getAport());
                        fdRequest.setDdate(fdDate);

                        list.add(fdRequest);
                    }
                }
            } else {
                return JsonResult.createJsonResult(-2, "什么情况");
            }
        }
        int retCode = flightDao.createFdRequests(list);
        return JsonResult.createJsonResult(retCode);
    }

    @Override
    public List<FdResult> searchFdResult(int enterpriseId, CommonSearchCriteria sc) {
        return flightDao.searchFdResult(enterpriseId, sc);
    }

    @Override
    public CommonDto<FlightInfoDto> searchFlight(int enterpriseId, String username, String dcity0, String acity0, Date ddate,
                                                 final int source, String remoteAddr) {
        CommonDto<FlightInfoDto> results = new CommonDto<>();
        results.setDataList(new ArrayList<>());

        final String dcity = FlightUtil.verifyCityCode(dcity0);
        final String acity = FlightUtil.verifyCityCode(acity0);

        if (dcity.length() < 3 || acity.length() < 3 || ddate == null || DateUtil.getPastDays(ddate) > 0) {
          return results;
        }

        if (source == 0) {

            List<NameValuePair> params = new ArrayList<>();
            params.add(new BasicNameValuePair("dcity", dcity));
            params.add(new BasicNameValuePair("acity", acity));
            params.add(new BasicNameValuePair("ddate", DateUtil.formatDate(ddate, DATE_YYYY_MM_DD)));

            String jsonStr = HttpUtil.getUrl(apiUrl + "/rav?", params);

//            results = JSON.parseObject(jsonStr, CommonDto.class);
            results = JSON.parseObject(jsonStr, new TypeReference<>() {});

        } else if (source == 1) {
            //cz ndc
            var rq = new AirShoppingRequest();

            rq.getShoppingRequest().setDirectOnly(true);

            OriginDestRequest originDestRequest = new OriginDestRequest();
            originDestRequest.setOrigCityCode(dcity);
            originDestRequest.setDestCityCode(acity);
            originDestRequest.setTravelDate(ddate);
            rq.getShoppingRequest().getOriginDestRequests().add(originDestRequest);

            PaxQuery paxQuery = new PaxQuery();
            paxQuery.setPassengerType("ADT");
            paxQuery.setPassengerNumber(1);
            rq.getShoppingRequest().getPaxQueries().add(paxQuery);

            //记录查询日志
            final int queryId = userDao.createEtermCmdLog(enterpriseId, username, "CZ_NDC_查询航班", null);
            rq.getPayloadAttributes().setTransactionId(queryId + "");

            var ndcService = createNdcService(enterpriseId);
            var rs = ndcService.searchFlight(rq);
            userDao.updateEtermCmdLog(queryId, rs.getRequestStr(), rs.getResponseStr());

            if (SUCCESS.equalsIgnoreCase(rs.getStatus().getStatus())) {
                results.setDataList(new ArrayList<>());
                convertBaseShoppingResponse(rs.getResponse(), results);
            } else {
                results.setErrcode(10000);
                results.setErrmsg(rs.getStatus().getErrorCode() + ": " + rs.getStatus().getErrorMessage());
            }
        }

        return results;
    }

    @Override
    public IntlFlightResponseDto searchIntlFlight(int enterpriseId, int routeType, String dcity, String acity, Date ddate, Date adate, String remoteAddr, String openid) {
        if (dcity.length() < 3 || acity.length() < 3 || ddate == null || DateUtil.getPastDays(ddate) > 0) {
            IntlFlightResponseDto dto = new IntlFlightResponseDto();
            dto.setErrcode(100);
            dto.setErrmsg("查询参数错误");
            return dto;
        }

        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("routeType", routeType + ""));
        params.add(new BasicNameValuePair("dcity", dcity));
        params.add(new BasicNameValuePair("acity", acity));
        params.add(new BasicNameValuePair("ddate", DateUtil.formatDate(ddate, DATE_YYYY_MM_DD)));
        if (adate != null) {
            params.add(new BasicNameValuePair("adate", DateUtil.formatDate(adate, DATE_YYYY_MM_DD)));
        }

        String jsonStr = HttpUtil.getUrl(apiUrl + "/searchOne?", params);

        return JSON.parseObject(jsonStr, IntlFlightResponseDto.class);
    }

    @Override
    public List<FdRequest> searchFdRequest(int enterpriseId, CommonSearchCriteria sc) {
        return flightDao.searchFdRequest(enterpriseId, sc);
    }

    @Override
    public int deletePriceRequest(int enterpriseId, int id) {
        return flightDao.deleteFdRequest(enterpriseId, id);
    }

    @Override
    public int deleteAllPriceRequest(int enterpriseId) {
        Date curDateTime = DateUtil.getCurDateTime();
        curDateTime = DateUtil.addMinutes(curDateTime, -120);

        return flightDao.deleteAllFdRequest(enterpriseId, curDateTime);
    }

    @Override
    public int deleteAllPriceResult(int enterpriseId) {
        return flightDao.deleteAllFdResult(enterpriseId);
    }

    @Override
    public List<SkInfo> searchAirlineSchedules(CommonSearchCriteria sc) {
        return flightDao.searchAirlineSchedules(sc);
    }

    @Override
    public JsonResult execEtermCmd(final int enterpriseId, String hostcmd, String openid) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setStatus("ER");

        //记录发送指令
        userDao.createEtermCmdLog(enterpriseId, 0, hostcmd, openid);

        if (hostcmd == null || hostcmd.trim().length() < 2) {
            jsonResult.setErrmsg("命令长度至少要2个字符");
            return jsonResult;
        }

        hostcmd = hostcmd.trim();

        int idx = hostcmd.indexOf(' ');
        if (idx <= 0) {
            idx = hostcmd.indexOf(':');
        }

        final String mainCmd = idx > 0 ? hostcmd.substring(0, idx) : hostcmd;

        Set<String> allowedCmds = new HashSet<>();
        allowedCmds.add("AV");
        allowedCmds.add("FD");
        allowedCmds.add("NFD");
        allowedCmds.add("SK");
        allowedCmds.add("RT");
        allowedCmds.add("IG");
        allowedCmds.add("PN");
        allowedCmds.add("FF");
        allowedCmds.add("TSL");
        allowedCmds.add("TPR");
        allowedCmds.add("DETR");
        allowedCmds.add("RTKT");
        allowedCmds.add("QT");

        if (allowedCmds.contains(mainCmd.toUpperCase())) {
            BukEtermClient eterm = createEtermClient(enterpriseId);
            if (eterm == null) {
                //
                return JsonResult.createJsonResult(-1, "未找到可用eterm资源");
            }

            String cmdresult = null;
            try {
                String rs = eterm.readAvailableData();
                logger.info("rs: {}", rs);
                cmdresult = eterm.execCmd(hostcmd);
                //记录结果
                userDao.createEtermCmdLog(enterpriseId, 1, cmdresult, openid);

                if (cmdresult != null && cmdresult.length() > 7) {
                    cmdresult = cmdresult.substring(7);

                    String[] lines0 = cmdresult.split("\r");
                    List<String> list = new ArrayList<>();
                    for (String line : lines0) {
                        if (line.length() <= 80) {
                            list.add(line);

                        } else {
                            while (line.length() > 80) {
                                list.add(line.substring(0, 80));
                                line = line.substring(80);
                            }
                            if (line.length() > 0) {
                                list.add(line);
                            }
                        }
                    }

                    cmdresult = "";
                    for (String line : list) {
                        if (cmdresult.length() == 0) {
                            cmdresult += line;
                        } else {
                            cmdresult += "\r" + line;
                        }
                    }


                    jsonResult.setStatus("OK");
                    jsonResult.setDesc(cmdresult);

                } else {
                    jsonResult.setErrmsg("指令结果：" + cmdresult);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            jsonResult.setErrmsg("目前只支持 " + allowedCmds.toString());
        }

        return jsonResult;
    }

  @Override
  public FfDto searchFlightStopover(int enterpriseId, String flightNo, String ddate) {
      List<NameValuePair> params = new ArrayList<>();
      params.add(new BasicNameValuePair("flightNo", flightNo));
      params.add(new BasicNameValuePair("ddate", ddate));

      String jsonStr = HttpUtil.getUrl(apiUrl + "/eterm/ff?", params);

      logger.info(jsonStr);

      return JSON.parseObject(jsonStr, FfDto.class);

  }

  /**
     * 通过Excel文件生成运价下载请求
     * @param enterpriseId
     * @param fileName
     * @return
     */
    @Override
    public JsonResult createPriceRequestByExcel(final int enterpriseId, final String fileName) {
        List<FdRequest> list = new ArrayList<>();

        try {
            File target = new File(fileName);
            FileInputStream fi = new FileInputStream(target);
            Workbook wb = create(fi);

            importFdRequest(enterpriseId, list, wb);
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }

        if (list.isEmpty()) {
            return JsonResult.createJsonResult(-1, "没有数据");
        }

        EnterpriseBalance bal = enterpriseDao.getEnterpriseBalance(enterpriseId);

        if (bal == null || bal.getBitcoinBalance() < 5000) {
            logger.info("Your points must be greater than 5000.");
            return JsonResult.createJsonResult(-2, "积分余额需要5,000以上");
        }
        logger.info("Your points is {}", bal.getBitcoinBalance());

        int retCode = flightDao.createFdRequests(list);

        if (retCode > 0) {
            //扣除1000积分，通过EXCEL导入数据
            transactionDao.consumePoints(enterpriseId, 0, 1000, "用Excel导入运价下载请求（" + retCode + ")");
        }

        return JsonResult.createJsonResult(retCode);
    }


    private BukEtermClient createEtermClient(int enterpriseId) {
        EtermEntConfig cfg = enterpriseDao.searchEtermConfig(enterpriseId);
        if (cfg == null) {
          return  null;
        }

        BukEtermClient eterm = new BukEtermClient(cfg.getHost(), cfg.getPort(), cfg.getUsername(), cfg.getPassword(), 15000);
        eterm.connect();

        return eterm;
    }

    /**
     * 格式1的excel导入
     * 航司二字代码，出发机场，到达机场，日期（可选）
     * 数据从第二行开始
     */
    private void importFdRequest(final int enterpriseId, List<FdRequest> list, Workbook wb) {
        Sheet sheet = wb.getSheetAt(0);
        final int rowNum = sheet.getLastRowNum() + 1;

        for (int i = 1; i < rowNum; i++) {
            Row row = sheet.getRow(i);

            //航司2字代码
                final String carrier = row.getCell(0).getStringCellValue().trim().toUpperCase();
            final String dport = row.getCell(1).getStringCellValue().trim().toUpperCase();
            final String aport = row.getCell(2).getStringCellValue().trim().toUpperCase();

            Cell cell = row.getCell(3);

            final String ddate;
            if (cell != null) {
              ddate = cell.getStringCellValue().trim().toUpperCase();
            } else {
              ddate = "";
            }

            if (carrier.length() != 2 || dport.length() != 3 || aport.length() != 3) {
              continue;
            }

            FdRequest o = new FdRequest();
            o.setEnterpriseId(enterpriseId);
            o.setCarrier(carrier);
            o.setDport(dport);
            o.setAport(aport);


            Date fdDate = DateUtil.getTomorrowDate();

            try {
                if (ddate != null && ddate.length() == 10) {
                  fdDate = DateUtil.convertToDate(ddate, DATE_YYYY_MM_DD);
                }
            } catch (Exception e) {
                logger.error(e.getMessage());
            }

            o.setDdate(fdDate);

            list.add(o);
        }
    }

}
